package com.ds.lens.data.filter;

import com.ds.lens.data.common.constant.Constants;
import com.ds.lens.data.common.util.HttpUtil;
import com.ds.lens.data.security.AuthenticationFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

import static com.ds.lens.data.security.SecuritytConstants.*;

/**
 * @author Gerald Kou
 * @date 2019-04-10
 */
@Slf4j
@Configuration
public class ValidateFilter implements Filter {
    @Value("${lens.security.sso.host}")
    private String ssoHost;

    @Value("${lens.security.authentication}")
    private boolean authIsRequired;

    @Value("#{'${lens.security.whiteList.url}'.split(',')}")
    private List<String> uriWhiteList;

    @Value("#{'${lens.security.whiteList.ip}'.split(',')}")
    private List<String> ipList;

    private AntPathMatcher pathMatcher = new AntPathMatcher("/");

    @Autowired
    private AuthenticationFactory authenticationFactory;

    @Override
    public void init(FilterConfig config) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String requestURI = request.getRequestURI();
        if (!authIsRequired || LOGIN_URI.equals(requestURI) || LENS_LOGIN_URI.equals(requestURI) || checkWhiteList(request)) {
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            try {
                //鉴权
                int code = authentication(request);
                if (code == HttpServletResponse.SC_OK) {
                    filterChain.doFilter(request, response);
                } else {
                    response.sendError(code, ERROR_INFO);
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, ERROR_INFO);
            }
        }
    }

    private boolean checkWhiteList(HttpServletRequest request) {
        // 如果配置了IP白名单 则优先校验IP白名单 再校验URL白名单
        if (null == request) {
            return false;
        }
        String ip = HttpUtil.getIpAddress(request);
        if (CollectionUtils.isNotEmpty(ipList) && StringUtils.isNotEmpty(ip)) {
            for (String exclude : ipList) {
                if (exclude.trim().equals(ip.trim())) {
                    return true;
                }
            }
        }
        String path = request.getRequestURI();
        if (CollectionUtils.isNotEmpty(uriWhiteList) && StringUtils.isNotEmpty(path)) {
            for (String exclude : uriWhiteList) {
                if (pathMatcher.match(exclude, path)) {
                    return true;
                }
            }
        }
        return false;
    }

    private int authentication(HttpServletRequest request) throws Exception {
        int loginType = request.getIntHeader(LOGIN_TYPE) > 0 ? request.getIntHeader(LOGIN_TYPE) : Constants.UserTypeEnum.SSO.getCode();
        request.setAttribute(LOGIN_TYPE, loginType);
        return authenticationFactory.getAuthentication("authentication" + Constants.UserTypeEnum.enumOf(loginType).getName()).authentication(request);
    }

    @Override
    public void destroy() {
    }
}
